/**
 * Created with hong.rong
 * Description:上传hook
 * Date:2020/06/29
 */

import { useState, useEffect } from 'react'
import axios from 'axios'
import { message } from 'antd'
import { isString, isNumber, isArray, isFunction } from 'lodash'

let fileList = null

/**
 * 校验是否图片
 * @param imgName
 * @returns {boolean|PrimitiveChain<boolean>|LoDashExplicitWrapper<boolean>|_.LodashEndsWith1x1|*}
 */
const isImg = imgName => {
  return (
    imgName.endsWith('.png') ||
    imgName.endsWith('.gif') ||
    imgName.endsWith('.jpeg') ||
    imgName.endsWith('.jpg') ||
    imgName.endsWith('.bmp') ||
    imgName.endsWith('.PNG') ||
    imgName.endsWith('.GIF') ||
    imgName.endsWith('.JPEG') ||
    imgName.endsWith('.JPG') ||
    imgName.endsWith('.BMP')
  )
}

/**
 * 图片上传支持的尺寸单位
 * @type {{M: string, K: string}}
 */
export const SIZE_UNIT = {
  M: 'M',
  K: 'KB',
}

/**
 * 上传文件格式集合
 * @type {{IMAGE: string[], DOC: string[], ZIP: string[]}}
 */
export const MIME_TYPE = {
  IMAGE: [
    // 图片
    'jpg',
    'jpeg',
    'png',
    'gif',
    'csv',
  ],
  DOC: [
    // txt、doc、pdf
    'txt',
    'doc',
    'docx',
    'xml',
    'xlsx',
    'pdf',
    'ppt',
    'pptx',
  ],
  ZIP: [
    // zip
    'zip',
    'rar',
    '7z',
    'tar',
  ],
}

export default function useUpload({
  value,
  max, // 最大上传限制
  accept = [...MIME_TYPE.IMAGE, ...MIME_TYPE.DOC, ...MIME_TYPE.ZIP], // 上传文件类型
  size, // 上传尺寸限制
  unit, // 尺寸单位
  rate, // 图片分辨率, 仅支持图片上传. Array类型, index -> 0: 图片宽度, index -> 1: 图片高度
  onChange,
}) {
  const [loading, setLoading] = useState(false)
  const [previewVisible, setPreviewVisible] = useState(false)
  const [previewImage, setPreviewImage] = useState('')

  useEffect(() => {
    fileList = value || []
    return () => {
      fileList = null
    }
  }, [])

  /**
   * 获取image实例
   * @param file
   * @returns {Promise<any>}
   */
  const getImage = file => {
    return new Promise((resolve, reject) => {
      try {
        const reader = new FileReader()
        reader.readAsDataURL(file)
        reader.addEventListener('load', () => {
          const img = new Image()
          img.src = reader.result
          img.onload = function() {
            resolve(img)
          }
        })
      } catch (err) {
        reject(err)
      }
    })
  }
  /**
   * 预览
   * @param file
   * @returns {Promise<void>}
   */
  const handlePreview = async file => {
    if (isImg(file.name) && file.status === 'done' && file.url) {
      setPreviewImage(file.url || file.thumbUrl)
      setPreviewVisible(true)
      return
    }
    if (file.url) {
      window.location.href = file.url
    }
  }
  /**
   * 关闭弹框
   */
  const handleCancel = () => setPreviewVisible(false)
  /**
   * 上传前
   * @param file
   * @returns {Promise<*>}
   */
  const handleBeforeUpload = async file => {
    // 上传数量校验
    const fileList = value || []
    if (isNumber(max) && fileList.length >= max) {
      message.error('文件上传数量上限')
      return Promise.reject()
    }
    // 文件类型校验
    if (isArray(accept) && isString(file.name)) {
      const names = file.name.split('.')
      const suffix = names[names.length - 1]
      if (!accept.includes(suffix)) {
        message.error('文件上传格式错误')
        return Promise.reject()
      }
    }
    // 校验尺寸(仅支持图片上传)
    if (isArray(rate)) {
      const image = await getImage(file)
      if (image.width !== rate[0] || image.height !== rate[1]) {
        message.error(`文件上传尺寸仅支持 ${rate[0]}×${rate[1]}px`)
        return Promise.reject()
      }
    }
    // 大小校验
    if (isNumber(size) && isString(unit)) {
      let isLt = false
      switch (unit) {
        case SIZE_UNIT.M:
          isLt = file.size / 1024 / 1024 < size
          break
        case SIZE_UNIT.K:
          isLt = file.size / 1024 < size
          break
        default:
          break
      }
      if (!isLt) {
        message.error(`${file.name}文件上传大小不能超过${size}${unit}`)
        return Promise.reject()
      }
    }
    return true
  }
  /**
   * 删除
   * @param file
   */
  const handleRemove = file => {
    if (Array.isArray(value)) {
      fileList = value.filter(item => item.uid !== file.uid)
      isFunction(onChange) && onChange(fileList)
    }
  }
  /**
   * 上传事件
   * @param action
   * @param data
   * @param file
   * @param filename
   * @param headers
   * @param withCredentials
   * @param callback
   * @returns {*}
   */
  const handleCustomRequest = (
    { action, data, file, filename, headers, withCredentials },
    callback
  ) => {
    const formData = new FormData()
    if (data) {
      Object.keys(data).forEach(key => {
        formData.append(key, data[key])
      })
    }
    formData.append(filename, file)
    setLoading(true)
    try {
      if (loading) {
        return message.warning('正在上传...')
      }
      axios
        .post(action, formData, {
          withCredentials,
          headers: {
            ...headers,
            token: localStorage.getItem('token'),
          },
        })
        .then(({ data = {} }) => {
          if (data && data.code === 0) {
            message.success(`文件${file.name}上传成功`)
            fileList = (fileList || []).concat([
              {
                uid: file.uid,
                status: 'done',
                name: file.name || '',
                size: file.size / 1024,
                url: data.data || '',
              },
            ])
            isFunction(callback) && callback()
            isFunction(onChange) && onChange(fileList)
            setLoading(false)
          } else {
            message.error(data.msg)
            setLoading(false)
          }
        })
    } catch (e) {
      console.log('上传错误:', e)
      setLoading(false)
    }
    return {
      abort() {
        console.log('上传被终止')
      },
    }
  }

  return {
    loading,
    previewVisible,
    previewImage,
    handleBeforeUpload,
    handleRemove,
    handleCustomRequest,
    handlePreview,
    handleCancel,
  }
}
useUpload.SIZE_UNIT = SIZE_UNIT
useUpload.MIME_TYPE = MIME_TYPE
